﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Windows.Forms;

namespace ListItemEditor
{
    public class TreeViewDataSource
    {
        #region inner types

        public class TreeViewDataSourceEventArgs : EventArgs
        {
            public TreeNode TreeNode { get; set; }
        }

        #endregion

        #region variables

        private SiteMapProvider _provider;
        private TreeView _tree;

        #endregion

        #region events

        public event EventHandler<TreeViewDataSourceEventArgs> TreeNodeDataBound;

        #endregion

        #region properties

        public bool ShowRoot { get; set; }

        #endregion

        #region public methods

        public TreeViewDataSource(SiteMapProvider provider, TreeView tree)
        {
            this._provider = provider;
            this._tree = tree;
        }

        public void Disconnect()
        {
            _tree.BeforeExpand -= new TreeViewCancelEventHandler(_tree_BeforeExpand);
        }

        public void DataBind()
        {
            _tree.Nodes.Clear();

            _tree.BeforeExpand -= new TreeViewCancelEventHandler(_tree_BeforeExpand);
            _tree.BeforeExpand += new TreeViewCancelEventHandler(_tree_BeforeExpand);

            if (this.ShowRoot) this.CreateNode(_provider.RootNode, this._tree.Nodes);
            else
            {
                this.CreateChildNodes (_tree.Nodes, (ListSiteMapNode)_provider.RootNode);
            }
        }

        public void RefreshNode(TreeNode node)
        {
            ListSiteMapNode listNode = node.Tag as ListSiteMapNode;
            if (listNode == null) return;

            ((ISiteMapProviderRefreshable)this._provider).RefreshNode(listNode);

            node.Nodes.Clear();

            if (node.IsExpanded)
            {
                this.CreateChildNodes(node.Nodes, listNode);
            }
            else
            {
                this.AddDummyNode(node);
            }
        }

        public TreeNode FindTreeNode(string key)
        {
            ListSiteMapNode node = this._provider.FindSiteMapNode(key) as ListSiteMapNode;
            if (node == null) return null;
            return node.UserData as TreeNode;
        }

        #endregion

        #region event handlers

        private void _tree_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            TreeNode parent = e.Node;
            if ((parent.Nodes.Count <= 0) || parent.Nodes[0].Text.Equals("dummy"))
            {
                if (parent.Nodes.Count > 0)
                {
                    parent.Nodes.RemoveAt(0);
                }
                ListSiteMapNode siteMapNode = parent.Tag as ListSiteMapNode;
                if (siteMapNode != null)
                {
                    this.CreateChildNodes(parent.Nodes, siteMapNode);
                }
            }
        }

        #endregion

        #region private

        private void CreateNode(SiteMapNode siteMapNode, TreeNodeCollection nodeCollection)
        {
            TreeNode node = nodeCollection.Add(siteMapNode.Key, siteMapNode.Title);
            node.Tag = siteMapNode;
            ((ListSiteMapNode)siteMapNode).UserData = node;
            AddDummyNode(node);

            if (TreeNodeDataBound != null) TreeNodeDataBound(this, new TreeViewDataSourceEventArgs() { TreeNode = node });
        }

        private void CreateChildNodes(TreeNodeCollection nodes, ListSiteMapNode listNode)
        {
            foreach (SiteMapNode childMapNode in listNode.ChildNodes)
            {
                this.CreateNode(childMapNode, nodes);
            }
        }

        private void AddDummyNode(TreeNode node)
        {
            node.Nodes.Add("dummy", "dummy");
        }

        #endregion
    }
}